<?php
/**
 * TinyMVC - TinyMVCException.class.php file
 *
 * @author Adrian Wieczorek <adi(at)tinymvc(dot)org>
 * @author Piotr Szymanski <bufoor(at)bluearrow(dot)org>
 * @package TinyMVC
 * @version $Id: TinyMVCException.class.php 116 2011-07-14 18:49:16Z adi3ek $
 *
 */

/**
 * core framework exception class
 * @package TinyMVC
 */
class TinyMVCException extends Exception {

	public function __construct($message, $code = 0) {
		parent::__construct($message, $code);
	}

	/**
	 * display full html exception trace page
  * @param Exception $exception Exception object (optional)
	 * @return string exception page
	 */
	protected function getHtmlTrace(Exception $exception = null) {
		if(is_object($this) && ($exception == null)) {
		 $exception = $this;
		}

		$trace = '<style type="text/css">
														body { margin-top:5px;	padding:0px; font-family:verdana, arial, helvetica, sans-serif; font-size: 11px; color:#000000;	background:white; }
														div.err_border {border: 1px solid black; margin: 2px; background: #f4f4f4;}
														div.err_line {padding: 2px; color: gray;}
														div.err_error {padding: 2px; color:red; font-size: 12pt; }
														div.err_arg {padding-left: 30px; font-size: 8pt; font-family: Courier New; color: black;}
														div.err_source {font-size: 10pt; font-family: Courier New; padding: 5px; color: blue;}
														span.err_source_line {color: white; font-weight: bold; background: blue;}
											</style>';

		$trace .= '<hr size="1"/>';
		$trace .= '<body>';
		$trace .= '<div class="err_error"><b>' . get_class($exception) . '</b>:  ' . $exception->getMessage() . '<br /><br /><b>Thrown by:</b> ' . $exception->getFile() . '  <b>at line:</b> ' . $exception->getLine() . '</div><br />';

  $backtrace = $exception->getTrace();
		if(count($backtrace)) {
			$html = '<div class="err_error"><b>Backtrace:</b></div>';
			foreach($backtrace as $item) {
				$html .= '<div class="err_border">';
				$html .= isset($item['file']) ? '<div class="err_line"><b>file:</b> ' . $item['file'] . '</div>' : '';
				$html .= isset($item['line']) ? '<div class="err_line"><b>line:</b> ' . $item['line'] . '</div>' : '';
				$html .= isset($item['function']) ? '<div class="err_line"><b>function:</b> ' . $item['function'] . '</div>' : '';
				$html .= isset($item['class']) ? '<div class="err_line"><b>class:</b> ' . $item['class'] . '</div>' : '';
				$html .= isset($item['type']) ? '<div class="err_line"><b>type:</b> ' . $item['type'] . '</div>' : '';
				if(count($item['args'])) {
					$html .= '<div class="err_line"><b>args:</b></div>';
					$html .= "<pre>";
					foreach($item['args'] as $key => $agr) {
						$html .= '<div class="err_arg">[' . $key . '] => ' . print_r($agr, true) . '</div>';
					}
					$html .= "</pre>";
				}
				if(isset($item['file']) && isset($item['line'])) {
					$source = $this->dumpSource($item['file'], $item['line']);
					if($source) {
						$html .= '<div class="err_line"><b>source:</b>';
						$html .= '<div class="err_source">';
						$html .= $source;
						$html .= '</div>';
						$html .= '</div>';
					}
				}
				$html .= '</div><br />';
   }
			$trace .= $html;
		}
		$trace .= '</body>';
		return $trace;
 }

 /**
  * handle exception
  * @param Exception $exception Exception object (optional)
  */
 public function handleException(Exception $exception = null) {
		$htmlTrace = $this->getHtmlTrace($exception);

		header('Content-Type: text/html; charset=utf-8');
		print $htmlTrace;
 }

	protected function dumpSource($file, $line) {
		$source = explode("\n", file_get_contents($file, true));
		$result = '';
		for ($index = $line-4; $index <= $line + 4; $index++) {
			if(isset($source[$index-1])) {
				$result	.=	(($index == $line) ? '<span class="err_source_line"' : '') . "<span>$index</span>: ";
				$result	.=	trim(str_replace(' ', '&nbsp;', htmlentities($source[$index-1])));
				$result	.=	($index == $line) ? '</span>' : '';
				$result	.=	"<br />\n";
			}
  }
  return $result;
	}
}
